﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Reflection;

namespace AudioPlayer.Plugin {
	/// <summary>
	/// Hold all plugins
	/// </summary>
	internal class PluginHash {
		#region Fields
		private Dictionary<Guid,PluginBase> _plugins;
		#endregion
		#region Constructor
		public PluginHash() {
			_plugins = new Dictionary<Guid, PluginBase>();
		}
		#endregion
		#region Private Voids
		private void IsTypeOf(Type a, Type b) {

		}
		#endregion
		#region Public Voids
		/// <summary>
		/// Adds the specified plugin.
		/// </summary>
		/// <param name="plugin">The plugin.</param>
		public void Add(PluginBase plugin) {
			if (!this.Contains(plugin.Guid)) {
				_plugins.Add(plugin.Guid, plugin);
			}
		}
		/// <summary>
		/// Removes the specified plugin.
		/// </summary>
		/// <param name="plugin">The plugin.</param>
		public void Remove(PluginBase plugin) {
			_plugins.Remove(plugin.Guid);
		}
		/// <summary>
		/// Determines whether plugin containers contains plugin with the specified key.
		/// </summary>
		/// <param name="key">The key.</param>
		/// <returns>
		/// 	<c>true</c> if contains specified key; otherwise, <c>false</c>.
		/// </returns>
		public bool Contains(Guid key) {
			if (_plugins.ContainsKey(key)) {
				return true;
			}
			return false;
		}
		/// <summary>
		/// Loads all plugins.
		/// </summary>
		public void LoadAll() {			
			foreach (KeyValuePair<Guid, PluginBase> entry in _plugins) {
				try {
					entry.Value.Load();
				} catch {
					#if DEBUG
					throw new Exception("Plugin failed to load itself");
					#endif
				}
			}
		}
		/// <summary>
		/// Unloads all plugins.
		/// </summary>
		public void UnloadAll() {
			foreach (KeyValuePair<Guid, PluginBase> entry in _plugins) {
				try {
					entry.Value.Unload();
				} catch {
					#if DEBUG
					throw new Exception("Plugin failed to unload itself");
					#endif
				}
			}
		}
		/// <summary>
		/// Return array list of current items.
		/// </summary>
		/// <returns></returns>
		public PluginBase[] ToArray() {
			List<PluginBase> list = new List<PluginBase>();
			lock (_plugins) {
				foreach (KeyValuePair<Guid, PluginBase> entry in _plugins) {
					list.Add(entry.Value);
				}
			}
			return list.ToArray();
		}

		/// <summary>
		/// Finds the one.
		/// </summary>
		/// <typeparam name="TPlugin">The type of the plugin.</typeparam>
		/// <returns></returns>
		public PluginBase<TPlugin> FindOne<TPlugin>() {
			lock (_plugins) {
				foreach (KeyValuePair<Guid, PluginBase> entry in _plugins) {
					if (entry.Value != null) {
						//Check if it's ok interface
						if (entry.Value.Type.GetInterface(typeof(TPlugin).FullName) != null) {
							PluginBase<TPlugin> bs = (PluginBase<TPlugin>)entry.Value;
							return bs;
						}
					}
				}
			}
			return null;
		}

		/// <summary>
		/// Finds all.
		/// </summary>
		/// <typeparam name="TPlugin">The type of the plugin.</typeparam>
		/// <returns></returns>
		public PluginBase<TPlugin>[] FindAll<TPlugin>() {
			//First check if TPlugin is IPlugin
			//Or looking plugin has anything todo with IPlugin
			bool plgIPlugin = (typeof(TPlugin) == typeof(IPlugin));
			bool plgOther = (typeof(TPlugin).GetInterface(typeof(IPlugin).FullName) != null);
			if (plgIPlugin || plgOther){
				//Lock
				lock (_plugins) {
					//Create a list
					List<PluginBase<TPlugin>> list = new List<PluginBase<TPlugin>>();
					//Loop through
					foreach (KeyValuePair<Guid, PluginBase> entry in _plugins) {
						//Check if value is ok
						if (entry.Value != null) {
							//Check if it's ok
							if (entry.Value.Type.GetInterface(typeof(TPlugin).FullName) != null) {
								list.Add((PluginBase<TPlugin>)entry.Value);
							}
						}
					}
					return list.ToArray();
				}
			}
			return null;
		}
		#endregion
		#region Property
		/// <summary>
		/// Gets the count.
		/// </summary>
		/// <value>The count.</value>
		public int Count {
			get {
				return _plugins.Count;
			}
		}

		/// <summary>
		/// Gets or sets the <see cref="AudioPlayer.Plugin.PluginBase"/> with the specified key.
		/// </summary>
		/// <value></value>
		public PluginBase this[Guid key] {
			get {
				if (this.Contains(key)) {
					return _plugins[key];
				}
				return null;
			}
			set {
				_plugins[key] = value;
			}
		}
		#endregion
	}
}
